﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Caching.Redis;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using StackExchange.Redis;

namespace Company.Utility
{
    public sealed class DataCache
    {
        private static object _lock = new object();
        //private static readonly IMemoryCache MemoryCache = new MemoryCache(new MemoryCacheOptions()); //采用redis作为cache依赖
        private static IDatabase _cache;
        private ConnectionMultiplexer _connection;
        private static string _instanceName;
        public DataCache()
        {
            var options = new RedisCacheOptions
            {
                Configuration = ReadConfig.ReadAppSetting("RedisConn"),
                InstanceName = "Company.Project.Cache"
            };
            int database = 0;
            _connection = ConnectionMultiplexer.Connect(options.Configuration);
            _cache = _connection.GetDatabase(database);
            _instanceName = options.InstanceName;
        }
        /// <summary>
        /// 生成缓存key
        /// </summary>
        /// <param name="key">缓存的键</param>
        /// <returns>缓存的值</returns>
        private string GetKeyForRedis(string key)
        {
            return _instanceName + key;
        }
        /// <summary>
        /// 判断缓存是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Exists(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentNullException(nameof(key));


            return _cache.KeyExists(GetKeyForRedis(key));
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T GetCache<T>(string key) where T : class
        { 
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentNullException(nameof(key));


            var value = _cache.StringGet(GetKeyForRedis(key));
            if (!value.HasValue)
                return default(T);


            return JsonConvert.DeserializeObject<T>(value);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void SetCache(string key, object value)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentNullException(nameof(key));
            if (value == null)
                throw new ArgumentNullException(nameof(value));


            if (Exists(GetKeyForRedis(key)))
                RemoveCache(GetKeyForRedis(key));


            _cache.StringSet(GetKeyForRedis(key), JsonConvert.SerializeObject(value));
        }
        /// <summary>
        /// 设置缓存带过期时间
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expiressAbsoulte"></param>
        public void SetCache(string key, object value, TimeSpan expiressAbsoulte)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentNullException(nameof(key));
            if (value == null)
                throw new ArgumentNullException(nameof(value));


            if (Exists(GetKeyForRedis(key)))
                RemoveCache(GetKeyForRedis(key));


            _cache.StringSet(GetKeyForRedis(key), JsonConvert.SerializeObject(value), expiressAbsoulte);
        }

        /// <summary>
        /// 移除缓存
        /// </summary>
        /// <param name="key"></param>
        public void RemoveCache(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentNullException(nameof(key));


            _cache.KeyDelete(GetKeyForRedis(key));
        }

        /// <summary>
        /// 强制回收redis连接
        /// </summary>
        public void Dispose()
        {
            if (_connection != null)
                _connection.Dispose();
            GC.SuppressFinalize(this);
        }
    }
}
